package ks.client.game.wordsteal;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Properties;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

import wordsteal.boundaries.main.MainJPanel;
import wordsteal.entities.Dictionary;
import wordsteal.entities.Game;
import wordsteal.entities.Player;
import wordsteal.entities.ReqTilesPerTurn;

import ks.client.game.GameFrame;
import ks.client.game.GameInformation;
import ks.client.timer.TimerPanel;
import ks.client.timer.TimerUpdate;

public class WordstealGameInformation extends GameInformation {

	boolean pink;
	boolean noS;
	int turnTime;
	int pointsToWin;
	
	/** Enclosing game frame. */
	GameFrame frame;
	
	/** Game container. */
	MainJPanel gameContainer = null;
	
	/** Controls. */
	JPanel controlPanel = null;
	JButton submitButton = null;
	JButton skipButton = null;
	TimerPanel timerPanel = null;
	
	/** Is game complete? reset in start. Set in stop. */
	boolean isGameComplete = false;
	
	/**
	 * Options for solitaire include:
	 * 
	 * pink<boolean>     determine whether board clears on Pink play.
	 * noS<boolean>      prevent or allow S extensions to words
	 * turnTime<int>     time for each turn
	 * pointsToWin<int>  score at which game finishes
	 * 
	 * @param options
	 * @param gameOptions
	 */
	public WordstealGameInformation(Properties options, Properties gameOptions) {
		super(options);
		
		// set pink option
		String pinkS = gameOptions.getProperty("pink");
		if (pinkS == null) {
			pink = true; //defaults
		} else {
			try {
				pink = Boolean.valueOf(pinkS);
			} catch (Exception e) {
				e.printStackTrace();
				pink = true;
			}
		}
		
		// set noS option
		String noSS = gameOptions.getProperty("noS");
		if (noSS == null) {
			noS = true; //defaults
		} else {
			try {
				noS = Boolean.valueOf(noSS);
			} catch (Exception e) {
				e.printStackTrace();
				noS = true;
			}
		}
		
		// set turntime option
		String turnTimeS = gameOptions.getProperty("turnTime");
		if (turnTimeS == null) {
			turnTime = 30; //defaults
		} else {
			try {
				turnTime = Integer.valueOf(turnTimeS);
			} catch (Exception e) {
				e.printStackTrace();
				turnTime = 30;
			}
		}
		
		// set score finishing option
		String pointsToWinS = gameOptions.getProperty("pointsToWin");
		if (pointsToWinS == null) {
			pointsToWin = 30; //defaults
		} else {
			try {
				pointsToWin = Integer.valueOf(pointsToWinS);
			} catch (Exception e) {
				e.printStackTrace();
				pointsToWin = 30;
			}
		}
	}

	/**
	 * Because this is a turn-based game, initially the lobby is locked
	 * while the moderator (first one) gets a chance.
	 */
	@Override
	public boolean start(GameFrame frame) {
		this.frame = frame;
		frame.setVisible(true);
		frame.setTitle("WordSteal by Dan Sacco, Soe San Winn, and Zach Broderick");
		frame.setSize (800, 768);
		
		// necessary?
		//frame.addMouseListener(((MainJPanel)getGameContainer()).moveTileController());
		//frame.addMouseMotionListener(((MainJPanel)getGameContainer()).moveTileController());
		
		ArrayList<wordsteal.entities.Player> list = new ArrayList<wordsteal.entities.Player>();
		
		Color[] colors = { Color.red, Color.orange, Color.blue, Color.green };
		int i = 0;
		for (String pid : order) {
			String name = fullName(pid);
			list.add(new wordsteal.entities.Player(name, colors[i++]));
		}
		
		Dictionary dict = null;
		try {
			dict = new Dictionary("../StandAlone/Dictionaries/english.txt");
		} catch (Exception e) {
			try {
				dict = Dictionary.createDefaultDictionary();
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
				return false;
			}
		}
		
		// make sure dictionary uses proper seed
		dict.setSeed(seed);
		
		//Create a new game using new game information
		Game newGame = new Game(list, dict);
		newGame.setNoPinkEnabled(pink);
		newGame.setNoSEnabled(noS);
		newGame.setPointsToWin(pointsToWin);
		newGame.setReqTilesPerTurn(ReqTilesPerTurn.Normal);
		newGame.setTimePerTurn(turnTime);
				
		// set game and refresh GUI to kick things off. Because
		// code bases are separate we have a bridge controller
		// to ensure outgoing events are handled.
		((MainJPanel)getGameContainer()).setGame(newGame);
		((MainJPanel)getGameContainer()).setCallback(new BridgeCallback(callback, frame.getTableNumber()));
		
		
		// need table number for skip controller...
		((MainJPanel)getGameContainer()).setTableNumber(frame.getTableNumber());
		((MainJPanel)getGameContainer()).refreshGUI();
		
		// must lock GUI and let (at a later time) the moderator begin things
		// off. This is a tricky handshake and doesn't happen for Solitaire
		// games.
		((MainJPanel)getGameContainer()).lockUI(true);
		isGameComplete = false;
		return true;
	}

	@Override
	public Component getGameControls() {

		if (controlPanel == null) {
			controlPanel = new JPanel();
				
			GroupLayout layout = new GroupLayout(controlPanel);
			controlPanel.setLayout(layout);
			layout.setAutoCreateGaps(true);
			layout.setAutoCreateContainerGaps(true);
			
			timerPanel = new TimerPanel();
			timerPanel.setMaximumSize(new Dimension (100, 40));
			
			submitButton = new JButton ("Submit");
			submitButton.addActionListener (new ActionListener() {
	
				@Override
				public void actionPerformed(ActionEvent e) {
					SubmitWordController swc = new SubmitWordController((MainJPanel)getGameContainer());
					
					swc.process(WordstealGameInformation.this, callback);
				}
				
			});
			
			// initially not responsive
			submitButton.setEnabled(false);
			
			skipButton = new JButton ("Skip Turn");
			skipButton.addActionListener (new ActionListener() {
	
				@Override
				public void actionPerformed(ActionEvent e) {
					MainJPanel mjp = (MainJPanel)getGameContainer();
					SkipSelfTurnController stc = new SkipSelfTurnController(mjp);
					stc.process(WordstealGameInformation.this, callback);				}
			});
			
			// initially not responsive
			skipButton.setEnabled(false);

			timerPanel.setMaster(new TimerUpdate() {
	
				@Override
				public void minorTick() {
					
				}

				@Override
				public void timerExpired() {
					// if we are expiring AND IT IS OUR TURN, then act
					// differently than if timer is expiring while
					// we are active. How to know? IF GUI is locked
					// then OPPONENT; if now, then US
					MainJPanel mjp = (MainJPanel)getGameContainer();
					if (mjp.isLockedUI()) {
						// opponent. DO NOTHING
					} else {
						SkipSelfTurnController stc = new SkipSelfTurnController(mjp);
						stc.process(WordstealGameInformation.this, callback);		
					}
				}
				
			});
			
			layout.setHorizontalGroup(layout.createSequentialGroup()
					.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
							.addComponent(timerPanel)
							.addComponent(submitButton)
							.addComponent(skipButton))
					);
			
			layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
					.addGroup(layout.createSequentialGroup()
							.addComponent(timerPanel)
							.addComponent(submitButton)
							.addComponent(skipButton))
					);
							
		}
		
		return controlPanel;
	}

	@Override
	public Component getGameContainer() {
		if (gameContainer == null) {
			gameContainer = new MainJPanel();
			
		}
		
		return gameContainer;
	}

	@Override
	public void initialize() {
		// TODO Auto-generated method stub
		
	}

	/**
	 * Stop wordsteal game. Future attempts to activate turns for
	 * this game will be denied.
	 */
	@Override
	public void stop() {
		// must stop underlying timer panel thread...
		timerPanel.stop();
		
		isGameComplete = true;
	}

	/**
	 * Extract points in preparation for returning to kombatGames.
	 * 
	 * @param players
	 * @return
	 */
	public static Properties extractScores(ArrayList<Player> players) {
		Properties props = new Properties();
		for (Player p : players) {
			// of the form "jsaldjljd [id]". Extract id.
			int idx = p.name.indexOf('[');
			int end = p.name.indexOf(']');
			
			String id = p.name.substring(idx+1, end);
			props.setProperty(id, "" + p.getPoints());
		}
		
		return props;
	}

	/**
	 * Acts by locking/unlocking interface for user action.
	 * <p>
	 * The player is the one whose turn is becoming active.
	 * <p>
	 * @param playerID   player whose turn has becom active.
	 * @return <code>false</code> if game is over; <code>true</code> otherwise.
	 */
	@Override
	public boolean activateTurn(String playerID) {
		super.activateTurn(playerID);
		
		if (isGameComplete) {
			return false;
		}
		
		Game game = gameContainer.getGame();
		//int idx = game.getCurrentPlayer();
		Player curPlayer = game.findPlayer(fullName(playerID));
		
		gameContainer.activatePlayer(curPlayer.name);
		
		submitButton.setEnabled(true);
		skipButton.setEnabled(true);
		timerPanel.start(turnTime);
		
		if (playerID.equals (this.player)) {
			gameContainer.lockUI(false);
			return true;
		}
		
		gameContainer.lockUI(true);
		return true;
	}

	// immediately reset the timer as requested.
	public void resetTimer() {
		timerPanel.start(turnTime);
	}
	
	@Override
	public boolean makeTurn(String playerID, String moveString) {
		super.makeTurn(playerID, moveString);
		
		// apply this move
		// (6/9)=E,(6/8)=O,(6/7)=H,(6/6)=S 
		return new MakeTurnController((MainJPanel)getGameContainer()).process(this, callback, fullName(playerID), moveString);
		
	}

	// can't just ignore this playerID, right?
	@Override
	public boolean skipTurn(String playerID) {
		super.skipTurn(playerID);
		return new SkipTurnController((MainJPanel)getGameContainer()).process(this, callback);
	}

	/**
	 * Properly deal with in internal game as well.
	 * 
	 * Must pass in full name since that is used internally in the game.
	 */
	@Override
	public boolean requestLeave(String playerID) {
		new SkipTurnController((MainJPanel)getGameContainer()).process(this, callback);
		
		boolean rc = new RemovePlayerController((MainJPanel)getGameContainer()).process(callback, fullName(playerID));
		rc = rc & super.requestLeave(playerID);
		return rc;
	}

	/**
	 * Determine if playerID is current.
	 * 
	 * @param playerID
	 * @return
	 */
//	boolean isCurrentPlayer(String playerID) {
//		String full = fullName(playerID);
//		Game game = ((MainJPanel)getGameContainer()).getGame();
//		int idx = game.getCurrentPlayer();
//		Player p = game.getPlayer(idx);
//		if (p == null) { return false; }
//			
//		return full.equals(p.name);
//	}

	/** Activate or deactivate buttons as needed. */
	public void enableButtons(boolean b) {
		skipButton.setEnabled(b);
		submitButton.setEnabled(b);
	}

	@Override
	public boolean updateScores(Properties updatedScores, Properties updatedGame) {
		System.err.println("WordSteal does not expect updatedScores message.");
		return false;
	}
}
